﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace Allegro.TaskExecution
{
    /// <summary>
    /// Task interface
    /// </summary>
    public interface ITask : IIdentity
    {
        /// <summary>
        /// Root task. Null if this is the root task
        /// </summary>
        ITask RootTask { get; }

        /// <summary>
        /// Parent task. Null if this is the root task
        /// </summary>
        ITask ParentTask { get; set; }

        /// <summary>
        /// True if the task can be executed in the specified context
        /// </summary>
        bool CanExecute(IExecutionContext context);

        /// <summary>
        /// Execute the task. Before the task can be executed, a context must be registered for the task
        /// </summary>
        void Execute(IExecutionContext context);

        /// <summary>
        /// Associated task activity. This is an application object that can be executed by the task
        /// </summary>
        ITaskActivity Activity { get; set; }

        /// <summary>
        /// Configure the task to wait on another task. Multiple tasks may 
        /// be waited on. Note that the task will only wait on the task in
        /// the same execution context
        /// </summary>
        /// <param name="task"></param>
        void DependsOn(ITask task);

        /// <summary>
        /// Ask for notification on task progress in a particular context
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="context"></param>
        void NotifyProgress(TaskExecutionProgressNotification callback, IExecutionContext context);
    }
    /// <summary>
    /// 
    /// </summary>
    public static class TaskBreakpoints
    {
        /// <summary>
        /// Breakpoint at the beginning of the task
        /// </summary>
        public const string Begin = "B";

        /// <summary>
        /// Breakpoint at the end of the task
        /// </summary>
        public const string End = "E";
    }
    /// <summary>
    /// Interface for task debugging
    /// </summary>
    public interface ITaskDebug
    {
        /// <summary>
        /// Breakpoints
        /// </summary>
        IList<string> BreakPoints { get; }
    }
    /// <summary>
    /// 
    /// </summary>
    public interface ICompositeTask : ITask, ICompositeItem<ITask>
    {
        /// <summary>
        /// Child tasks
        /// </summary>
        TaskCollection Tasks { get; }

        /// <summary>
        /// Add a child task to the composite task
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        ICompositeTask AddTask(ITask item);

        /// <summary>
        /// Add a child task to the composite task with an estimated elapsed time.
        /// The elapsed time estimate is only used for progress computation and is used 
        /// as a relative weight between sibling tasks.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="elapsedTimeEstimateInSeconds">Estimated elapsed time in seconds</param>
        /// <returns></returns>
        ICompositeTask AddTask(ITask item, double elapsedTimeEstimateInSeconds);

        /// <summary>
        /// Get the elapsed time estimate for a given child task
        /// </summary>
        /// <param name="childTask"></param>
        /// <returns></returns>
        double GetEstimatedDuration(ITask childTask);
    }
    ///<summary>
    ///</summary>
    public enum ProgressEventType
    {
        ///<summary>
        ///</summary>
        TaskStarted = 0,
        ///<summary>
        ///</summary>
        TaskProgress = 1,
        ///<summary>
        ///</summary>
        TaskCompleted = 2,
        ///<summary>
        ///</summary>
        TaskAborted = 3,
        ///<summary>
        ///</summary>
        TaskSuspended = 4,
        ///<summary>
        ///</summary>
        TaskResumed = 5,
        ///<summary>
        ///</summary>
        TaskBreaked = 6,
    }

    /// <summary>
    /// Progress event notification delegate. progress is a fraction between 0 and 1
    /// </summary>
    /// <param name="eventType"></param>
    /// <param name="progress">Progress as a fraction between 0 and 1</param>
    /// <param name="message">Additional progress information</param>
    /// <param name="task"></param>
    /// <param name="context"></param>
    public delegate void TaskExecutionProgressNotification(ITask task, IExecutionContext context, ProgressEventType eventType, double progress, string message);

    /// <summary>
    /// Interface for controlling the sequence of asynchronous task execution
    /// </summary>
    public interface ITaskControl
    {
        /// <summary>
        /// WaitHandle that will be signaled when the task completes.
        /// </summary>
        EventWaitHandle CompletionEvent(ITaskContextCoordination context);

        /// <summary>
        /// Pre execution control
        /// </summary>
        void PreExecute(ITaskContextCoordination context);

        /// <summary>
        /// Post execution control
        /// </summary>
        void PostExecute(ITaskContextCoordination context);

        /// <summary>
        /// Compute progress of this task in the given context
        /// </summary>
        /// <param name="context"></param>
        void ComputeProgress(IExecutionContext context);
    }

    /// <summary>
    /// 
    /// </summary>
    public enum CompletionType
    {
        /// <summary>
        /// Don't wait 
        /// </summary>
        None = 0,
        /// <summary>
        /// Wait for the completion of one task
        /// </summary>
        One = 1,
        /// <summary>
        /// Wait for the completion of all tasks
        /// </summary>
        All = 2,
    }
    /// <summary>
    /// TaskCompletion inteface
    /// </summary>
    public interface ITaskCompletion
    {
        /// <summary>
        /// Type of completion
        /// </summary>
        CompletionType Type { get; set; }

        /// <summary>
        /// Wait for completion
        /// </summary>
        /// <param name="tasks"></param>
        /// <param name="context"></param>
        void DependsOn(IEnumerable<ITask> tasks, IExecutionContext context);
    }
}
